package com.zhangh.summer.admin.support.ds.es.http;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.Consts;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description: http操作工具类
 * @author: zhanghui  zhanghlucky@163.com
 * @create: 2020-03-20 11:14
 **/
@Slf4j
public class HttpClientUtil {
	private final static RequestConfig REQUEST_CONFIG;//请求参数配置
	private final static int CONNECT_TIMEOUT=10*1000;//链接超时时间10s
	private final static int SOCKET_TIMEOUT=3*60*1000;//socket超时时间3min
	private final static int CONNECT_REQUEST_TIMEOUT=3*60*1000;//等待响应超时时间3min
	private final static Map<String, ResponseHandler> RESPONSE_HANDLER_MAP;//响应处理

	static{
		RequestConfig.Builder builder= RequestConfig.custom();
		builder.setSocketTimeout(SOCKET_TIMEOUT)
				.setConnectTimeout(CONNECT_TIMEOUT)
				.setConnectionRequestTimeout(CONNECT_REQUEST_TIMEOUT);
		REQUEST_CONFIG= builder.build();
		RESPONSE_HANDLER_MAP=new HashMap<>();
	}

	/**
	 * 发起get请求
	 * @param url 请求地址
	 * @param params 请求参数
	 * @return 请求结果
	 */
	public static String doGet(String url,Map<String,String> params){
		return doGet(url, params,null);
	}
	/**
	 * 发起get请求
	 * @param url 请求地址
	 * @param params 请求参数
	 * @param traceId trace id
	 * @param groupID trace group id
	 * @return 请求结果
	 */
	public static String doGet(String url,Map<String,String> params,String traceId,Long groupID){
		return doGet(url,params,null,traceId,groupID);
	}
	/**
	 * 发起get请求
	 * @param url 请求地址
	 * @param params 请求参数
	 * @param headers header
	 * @return 请求结果
	 */
	public static String doGet(String url,Map<String,String> params,Map<String,String> headers){
		return doGet(url,params,headers,null,-1L);
	}

	/**
	 *发起get请求
	 * @param url 请求地址
	 * @param params 请求参数
	 * @param headers header
	 * @param traceId trace id
	 * @param groupID trace group id
	 * @return 请求结果
	 */
	public static String doGet(String url,Map<String,String> params,Map<String,String> headers,String traceId,Long groupID){
		List<NameValuePair> list = initNameValuePairList(params);
		if(list.size() > 0){
			UrlEncodedFormEntity entity= new UrlEncodedFormEntity(list, Consts.UTF_8);
			try {
				String urlParams= EntityUtils.toString(entity);
				if (url.contains("?")){
					url=url+"&"+urlParams;
				}else{
					url=url+"?"+urlParams;
				}
			} catch (IOException e) {
				log.error("params to url params io error:{}",e.getMessage());
			}
		}
		HttpGet httpGet = new HttpGet(url);
		return executeHttpRequest(httpGet,url,headers,traceId,groupID);
	}

	/**
	 * 发起post请求
	 * @param url 请求地址
	 * @param params 请求参数
	 * @param traceId trace id
	 * @param groupID trace group
	 * @return 请求结果
	 */
	public static String doPost(String url,Map<String,String> params ,String traceId,Long groupID){
		return doPost(url, params,null,traceId,groupID);
	}

	/**
	 * 发起post请求
	 * @param url 请求地址
	 * @param params 请求参数
	 * @param headers header
	 * @return 请求结果
	 */
	public static String doPost(String url,Map<String,String> params, Map<String,String> headers){
		return doPost(url, params,headers,null,-1L);
	}

	/**
	 * 发起post请求
	 * @param url 请求地址
	 * @param params 请求参数
	 * @param headers header
	 * @param traceId trace id
	 * @param groupID trace group id
	 * @return 结果
	 */
	public static String doPost(String url,Map<String,String> params,Map<String,String> headers,String traceId,Long groupID){
		HttpPost httpPost = new HttpPost(url);
		List<NameValuePair> list =initNameValuePairList(params);
		if(list.size() > 0){
			UrlEncodedFormEntity entity= new UrlEncodedFormEntity(list, Consts.UTF_8);
			httpPost.setEntity(entity);
		}
		return executeHttpRequest(httpPost,url,headers,traceId,groupID);
	}

	/**
	 * 提交POST请求
	 * @param url 请求地址
	 * @param json json数据
	 * @return 请求结果
	 */
	public static String doPost(String url,String json){
		return doPost(url,json,null,null,-1L);
	}
	public static String doPost(String url,String json,Map<String,String> headers){
		return doPost(url,json,headers,null,-1L);
	}

	/**
	 * 发起post请求
	 * @param url 请求地址
	 * @param json json request数据
	 * @param headers header
	 * @param traceId trace id
	 * @param groupID trace group id
	 * @return 结果
	 */
	public static String doPost(String url,String json,Map<String,String> headers,String traceId,Long groupID){
		HttpPost httpPost = new HttpPost(url);
		StringEntity requestEntity = new StringEntity(json,"UTF-8");
		requestEntity.setContentEncoding("UTF-8");
		httpPost.setHeader("Content-type", "application/json");
		httpPost.setEntity(requestEntity);
		return executeHttpRequest(httpPost,url,headers,traceId,groupID);

	}

	/**
	 * 上传文件
	 * @param filePath 文件路径
	 * @param url 上传地址
	 * @param multipartFileName 文件参数名称
	 * @param params 参数
	 * @return 结果
	 */
	public static String upload( String filePath,String url,String multipartFileName, Map<String,String> params) {
		return upload(filePath,url,multipartFileName,params,null,null,-1L);
	}

	/**
	 * 上传文件流
	 * @param inputStream 文件流
	 * @param fileName 文件名称
	 * @param url 上传地址
	 * @param multipartFileName 文件参数名称
	 * @param params 参数
	 * @return 结果
	 */
	public static String upload( InputStream inputStream,String fileName,String url,String multipartFileName, Map<String,String> params) {
		return upload(inputStream,fileName,url,multipartFileName,params,null,null,-1L);
	}

	/**
	 * 上传文件
	 * @param filePath 文件路径
	 * @param url 上传地址
	 * @param multipartFileName 文件参数名称
	 * @param params 参数
	 * @param headers header
	 * @return 上传结果
	 */
	public static String upload( String filePath,String url,String multipartFileName, Map<String,String> params,Map<String,String> headers) {
		return upload(filePath,url,multipartFileName,params,headers,null,-1L);
	}

	/**
	 * 上传文件流
	 * @param inputStream 文件流
	 * @param fileName 文件名称
	 * @param url 上传地址
	 * @param multipartFileName 文件参数名
	 * @param params 参数
	 * @param headers header
	 * @return 上传结果
	 */
	public static String upload( InputStream inputStream,String fileName,String url,String multipartFileName, Map<String,String> params,Map<String,String> headers) {
		return upload(inputStream,fileName,url,multipartFileName,params,headers,null,-1L);
	}

	/**
	 * 上传文件
	 * @param filePath 文件路径
	 * @param url 上传地址
	 * @param multipartFileName 文件参数名称
	 * @param params 参数
	 * @param headers header
	 * @param traceId trace id
	 * @param groupID trace group id
	 * @return 上传结果
	 */
	public static String upload( String filePath,String url,String multipartFileName, Map<String,String> params,Map<String,String> headers,String traceId,Long groupID) {
		try {
			InputStream inputStream=new FileInputStream(filePath);
			String fileName=filePath.substring(filePath.lastIndexOf("/")+1);
			return upload(inputStream,fileName,url,multipartFileName,params,headers,traceId,groupID);
		} catch (FileNotFoundException e) {
			log.error("upload file error:{}",e.getMessage());
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 上传文件流
	 * @param inputStream 文件流
	 * @param fileName 文件名称
	 * @param url 上传地址
	 * @param multipartFileName 文件参数名称
	 * @param params 参数
	 * @param headers header
	 * @param traceId trace id
	 * @param groupID group id
	 * @return 上传结果
	 */
	public static String upload(InputStream inputStream,String fileName, String url, String multipartFileName, Map<String,String> params, Map<String,String> headers, String traceId, Long groupID) {
		try {
			//String fileName=filePath.substring(filePath.lastIndexOf("/")+1);
			HttpPost httpPost = new HttpPost(url);
			MultipartEntityBuilder builder = MultipartEntityBuilder.create();
			builder.setCharset(StandardCharsets.UTF_8);
			builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
			builder.addBinaryBody(multipartFileName, inputStream, ContentType.MULTIPART_FORM_DATA, fileName);// 文件流
			for (Map.Entry<String, String> e : params.entrySet()) {
				if (null!=e.getValue()){
					builder.addTextBody(e.getKey(), e.getValue());
				}
			}
			HttpEntity entity = builder.build();
			httpPost.setEntity(entity);
			return executeHttpRequest(httpPost,url,headers,traceId,groupID);
		} catch (Exception e){
			log.error("upload file error :{},fileName:{},url:{}",e.getMessage(),fileName,url);
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 获得 结果处理器
	 * @param url 请求地址
	 * @return 结果处理器
	 */
	private  static ResponseHandler getResponseHandler(String url){
		return RESPONSE_HANDLER_MAP.computeIfAbsent(url, k -> response -> {
			if (response != null) {
				/*//trace 处理
				Header[] headers = response.getAllHeaders();
				for (Header header : headers) {
					if (header.getName().equals(TraceContext.TRACE_ID_KEY)) {
						TraceContext.setTraceId(header.getValue());
					}
					if (header.getName().equals(TraceContext.GROUP_ID_KEY)) {
						TraceContext.setGroupID(Long.valueOf(header.getValue()));
					}
				}*/

				HttpEntity resEntity = response.getEntity();
				if (resEntity != null) {
					String result;
					try {
						result = EntityUtils.toString(resEntity, "utf-8");
					} catch (ParseException e) {
						log.error("Parse response Exception：{}", e.getMessage());
						return null;
					} catch (IOException e) {
						log.error("Parse response io Exception：{}", e.getMessage());
						return null;
					}
					return result;
				}
			}
			log.error("http result is null");
			return null;
		});
	}

	/**
	 * 提交http请求
	 * @param httpRequestBase 请求
	 * @param url 地址
	 * @param headers header
	 * @param traceId trace id
	 * @param groupID trace group id
	 * @return 请求结果
	 */
	private static String executeHttpRequest(HttpRequestBase httpRequestBase, String url, Map<String, String> headers, String traceId, Long groupID) {
		httpRequestBase.setConfig(REQUEST_CONFIG);
		headers=initHeader(headers,traceId,groupID);//初始化headers数据
		for(Map.Entry<String, String> entry : headers.entrySet()){
			String name = entry.getKey();
			String value = entry.getValue();
			httpRequestBase.setHeader(name,value);
		}
		ResponseHandler<String> responseHandler=getResponseHandler(url);
		try {
			CloseableHttpClient httpClient= Client.SSLClient(url);
			return httpClient.execute(httpRequestBase,responseHandler);
		} catch (IOException e) {
			log.error("execute http response io error：{}",e.getMessage());
			return null;
		}
	}

	/**
	 * 初始化参数
	 * @param params 参数
	 * @return 参数集合
	 */
	private static List<NameValuePair> initNameValuePairList(Map<String,String> params){
		List<NameValuePair> list = new ArrayList<>();
		if (null!=params){
			for (Map.Entry<String, String> entry : params.entrySet()) {
				list.add(new BasicNameValuePair(entry.getKey(),entry.getValue()));
			}
		}
		return list;
	}

	/**
	 * 初始化header
	 * @param headers header
	 * @param traceId trace id
	 * @param groupID trace group id
	 * @return header map
	 */
	private static Map<String,String>  initHeader(Map<String,String> headers,String traceId,Long groupID){
		if (null==headers){
			headers=new HashMap<>();
		}
		/*if (StringUtils.isBlank(traceId)){
			traceId=headers.get(TraceContext.TRACE_ID_KEY);
			if (StringUtils.isBlank(traceId)){
				traceId=TraceContext.getTraceId();
				if (StringUtils.isBlank(traceId)){
					groupID=TraceContext.getGroupID();
					traceId=TraceManager.getInstance().startClientTrace().getTraceId();
					if (groupID>0){
						TraceContext.setGroupID(groupID);
					}
					log.info("param trace is null,header trade is null,thread local trace is null,create new trace:{}",traceId);
				}
			}
		}
		headers.put(TraceContext.TRACE_ID_KEY,traceId);

		if (groupID<=0){
			if (StringUtils.isNotBlank(headers.get(TraceContext.GROUP_ID_KEY))){
				try{
					groupID=Long.valueOf(headers.get(TraceContext.GROUP_ID_KEY));
				}catch (Exception e){
					log.error("get groupID from header error:{},key:{}",e.getMessage(),headers.get(TraceContext.GROUP_ID_KEY));
				}
			}else{
				groupID=TraceContext.getGroupID();
			}
		}
		if (groupID>0){
			headers.put(TraceContext.GROUP_ID_KEY,String.valueOf(groupID));
		}*/

		return headers;
	}

}
